#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <fstream>

#include "Common.hpp"

const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string HeaderLineSep = ": ";
const std::string BlankLine = "\r\n";

const std::string default_home_path = "wwwroot"; // 浏览器的请求的默认服务器路径
const std::string http_version = "HTTP/1.0";     // http的版本
const std::string page_404 = "wwwroot/404.html"; // 404页面
const std::string first_page = "index.html";     // 首页

// 浏览器/服务器模式(B/S): 浏览器充当客户端, 发送请求; 输入: 123.60.170.90:8080
class HttpRequset
{
public:
    HttpRequset() {}
    ~HttpRequset() {}

    // 浏览器具有自动识别http请求的能力, 可以充当客户端
    // 浏览器发送的http请求(序列化数据)如下:
    // GET /favicon.ico HTTP/1.1
    // Host: 123.60.170.90:8080
    // Connection: keep-alive
    // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0
    // Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
    // Referer: http://123.60.170.90:8080/
    // Accept-Encoding: gzip, deflate
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

    void ParseReqHeaderKV()
    {
        std::string key, value;
        for (auto &header : _req_header)
        {
            if (SplitString(header, HeaderLineSep, &key, &value))
            {
                _header_kv.insert(std::make_pair(key, value));
            }
        }
    }

    void ParseReqHeader(std::string &requset)
    {
        std::string line;
        while (true)
        {
            bool ret = ParseOneLine(requset, &line, Sep);
            if (ret && !line.empty())
            {
                _req_header.push_back(line);
            }
            else
            {
                break;
            }
        }
        // 提取请求报头每一行
        ParseReqHeaderKV();
    }

    // 解析请求行中详细的字段
    // GET /index.html HTTP/1.1
    void ParseReqLine(std::string &_req_line, const std::string &sep)
    {
        std::stringstream ss(_req_line);
        ss >> _req_method >> _uri >> _http_version;
    }

    // 对http请求进行反序列化
    void Deserialize(std::string &requset)
    {
        // 提取请求行
        if (ParseOneLine(requset, &_req_line, Sep))
        {
            // 提取请求行中的详细字段
            ParseReqLine(_req_line, LineSep);

            // 提取请求报文
            ParseReqHeader(requset);

            _blank_line = Sep;
            _req_body = requset;

            // 分析请求中是否含有参数
            if (_req_method == "POST") // 默认POST带参数
            {
                // 参数在正文_req_body部分: name=zhangsan&password=123456
                _isexec = true;
                _args = _req_body;
                _path = _uri;
            }
            else if (_req_method == "GET")
            {
                // 参数在URI中: login?name=zhangsan&password=123456
                auto pos = _uri.find("?"); 
                if (pos != std::string::npos) // 存在?带参数
                {
                    _isexec = true;
                    _path = _uri.substr(0, pos);
                    _args = _uri.substr(pos + 1);
                }
                else // 不存在?不带参数
                {
                    _isexec = false;
                }
            }
        }
    }

    // 返回请求的资源: uri
    std::string GetContent(const std::string &path)
    {
        // 既支持文本文件, 又支持二进制图片
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        return content;

        // 只支持读取文本文件, 不支持二进制图片
        // std::string content;
        // std::ifstream in(path);
        // if (!in.is_open())
        //     return std::string();
        // std::string line;
        // while (std::getline(in, line))
        // {
        //     content += line;
        // }
        // return content;
    }

    // 获取资源的文件后缀
    std::string Suffix()
    {
        // _uri -> wwwroot/index.html wwwroot/image/1.jpg
        auto pos = _uri.rfind(".");
        if (pos == std::string::npos)
            return std::string(".html");
        else
            return _uri.substr(pos);
    }

    std::string Uri() { return _uri; }
    void SetUri(const std::string newuri) { _uri = newuri; }
    std::string Path() { return _path; }
    std::string Args() { return _args; }
    bool IsHasArgs() { return _isexec; }

    void Print()
    {
        std::cout << "请求行详细字段: " << std::endl;
        std::cout << "_req_method: " << _req_method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_http_version: " << _http_version << std::endl;

        std::cout << "请求报头: " << std::endl;
        for (auto &kv : _header_kv)
        {
            std::cout << kv.first << " # " << kv.second << std::endl;
        }

        std::cout << "空行: " << std::endl;
        std::cout << "_blank_line: " << _blank_line << std::endl;

        std::cout << "请求正文: " << std::endl;
        std::cout << "_body: " << _req_body << std::endl;
    }

private:
    std::string _req_line;                                   // 请求行
    std::vector<std::string> _req_header;                    // 请求报头
    std::unordered_map<std::string, std::string> _header_kv; // 请求报头的KV结构
    std::string _blank_line;                                 // 空行
    std::string _req_body;                                   // 请求正文: 内部可能会包含参数(POST请求)

    // 请求行中详细的字段
    std::string _req_method;   // 请求方法
    std::string _uri;          // 用户想要的资源路径: 内部可能会包含参数(GET请求) /login.hmtl  |  /login?xxx&yyy
    std::string _http_version; // http版本

    // 关于请求传参GET/POST相关的结构
    std::string _path;    // 路径
    std::string _args;    // 参数
    bool _isexec = false; // 执行动态方法
};

// 对于http, 任何请求都要有应答
class HttpResponse
{
public:
    HttpResponse() {}
    ~HttpResponse() {}

    // 通过requset结构体, 构建response结构体
    void Build(HttpRequset &req)
    {
        // 当用户输入:
        // 123.60.170.90:8080/      -> 默认访问 wwwroot/index.html
        // 123.60.170.90:8080/a/b/  -> 默认访问 wwwroot/a/b/index.html

        std::string uri = default_home_path + req.Uri(); // wwwroot/
        if (uri.back() == '/')
        {
            uri += first_page; // wwwroot/index.html
            req.SetUri(uri);
        }

        // 获取用户请求的资源
        _content = req.GetContent(uri);
        if (_content.empty())
        {
            _status_code = 404; // 用户请求的资源不存在!
            req.SetUri(page_404);
            _content = req.GetContent(page_404); // 注意: 需要读取404页面
        }
        else
        {
            _status_code = 200; // 用户请求的资源存在!
        }
        _status_code_desc = CodeToDesc(_status_code);
        _resp_body = _content;

        // 设置响应报头
        SetHeader("Content-Length", std::to_string(_content.size()));
        std::string mime_type = SuffixToDesc(req.Suffix());
        SetHeader("Content-Type", mime_type);
    }

    // 设置响应报头的KV结构
    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }

    void SetCode(int code)
    {
        _status_code = code;
        _status_code_desc = CodeToDesc(_status_code);
    }   

    void SetBody(const std::string &body)
    {
        _resp_body = body;
    }

    // 对http响应序列化
    void Serialize(std::string *response)
    {
        // 1. 求各个字段
        for (auto &header : _header_kv)
        {
            _resp_header.push_back(header.first + HeaderLineSep + header.second);
        }
        _http_version = http_version;
        _resp_line = _http_version + LineSep + std::to_string(_status_code) + LineSep + _status_code_desc + Sep;
        _blank_line = BlankLine;

        // 2. 开始序列化: 各个字段相加
        *response = _resp_line;
        for (auto &line : _resp_header)
        {
            *response += (line + Sep);
        }
        *response += _blank_line;
        *response += _resp_body;
    }

private:
    // 将 状态码 转化为 状态码描述
    std::string CodeToDesc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        default:
            return std::string();
        }
    }

    // 将 文件后缀 转化为 文件类型
    std::string SuffixToDesc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".jpg")
            return "application/x-jpg";
        else
            return "text/html";
    }

private:
    std::string _resp_line;                                  // 响应行
    std::vector<std::string> _resp_header;                   // 响应报头
    std::unordered_map<std::string, std::string> _header_kv; // 响应报头的KV结构
    std::string _blank_line;                                 // 空行
    std::string _resp_body;                                  // 响应正文

    // 响应行中详细的字段
    std::string _http_version;     // http版本
    int _status_code;              // 状态码
    std::string _status_code_desc; // 状态码描述
    std::string _content;          // 返回给用户的内容: 响应正文
};